#!/usr/bin/perl

######################################################################
package Swignition::GenericParser::HTTP;
######################################################################

use Swignition::MagicString;
use Swignition::uF;
use DateTime;
use URI::URL;
use XML::LibXML qw(:all);
use strict;


sub is_enabled
{
	my $this = shift;
	
	return 1
		if ($this->{options}->{p_http} && $this->{RESPONSE});
		
	return 0;
}


sub consume
{
	my $this = shift;
	return unless ($this->{RESPONSE});
	my $nsrdf   = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
	my $nshttp  = 'http://www.w3.org/2006/http#';
	my $nshttpH = 'http://www.w3.org/2008/http-headers#';
	my $nshttpM = 'http://www.w3.org/2008/http-methods#';
	my $nshttpS = 'http://www.w3.org/2008/http-statusCodes#';
	my $rdftype = $nsrdf.'type';

	my $Response = Swignition::RDFModel::Subject->new(
		Swignition::GenericParser::Utils::BNodeURI(undef, 'HttpResponse'));
	$Response->addVal($rdftype, Swignition::RDFModel::Value->new($nshttp.'Response', 1));
	my $ResponseH = Swignition::RDFModel::Subject->new(
		Swignition::GenericParser::Utils::BNodeURI(undef, 'HttpResponseHeaders'));
	$ResponseH->addVal($rdftype, Swignition::RDFModel::Value->new($nsrdf.'List', 1));
	$Response->addVal($nshttp.'headers',
		Swignition::RDFModel::Value->new($ResponseH->uri, 1));

	my $Request = Swignition::RDFModel::Subject->new(
		Swignition::GenericParser::Utils::BNodeURI(undef, 'HttpRequest'));
	$Request->addVal($rdftype, Swignition::RDFModel::Value->new($nshttp.'Request', 1));
	my $RequestH = Swignition::RDFModel::Subject->new(
		Swignition::GenericParser::Utils::BNodeURI(undef, 'HttpRequestHeaders'));
	$RequestH->addVal($rdftype, Swignition::RDFModel::Value->new($nsrdf.'List', 1));
	$Request->addVal($nshttp.'headers',
		Swignition::RDFModel::Value->new($RequestH->uri, 1));
	$Request->addVal($nshttp.'response',
		Swignition::RDFModel::Value->new($Response->uri, 1));
	
	my $Subject = Swignition::RDFModel::Subject->new($this->uri);
	$Subject->addVal('http://buzzword.org.uk/rdf/http-ext#related-request',
		Swignition::RDFModel::Value->new($Request->uri, 1));

	my $i = 1;
	
	foreach my $header ( $this->{REQUEST}->headers->header_field_names )
	{
		my @h = $this->{REQUEST}->header($header);
		foreach my $h (@h)
		{
			my $huri = consume_header($this, $Subject, $header, $h);
			$RequestH->addVal('http://buzzword.org.uk/rdf/list-items/_'.$i,
				Swignition::RDFModel::Value->new($huri, 1));
			$i++;
		}
	}
	
	my $rproto = $this->{REQUEST}->protocol;
	$rproto =~ s|^HTTP/||;
	
	$Request->addVal($nshttp.'httpVersion',
		Swignition::RDFModel::Value->new($rproto))
		if ($rproto);
	$Request->addVal($nshttp.'method',
		Swignition::RDFModel::Value->new($nshttpM.uc($this->{REQUEST}->method), 1));
	$Request->addVal($nshttp.'methodName',
		Swignition::RDFModel::Value->new($this->{REQUEST}->method));
	my $val = Swignition::RDFModel::Value->new($this->{REQUEST}->uri);
	$val->setDatatype('http://www.w3.org/2001/XMLSchema#anyURI');
	$Request->addVal($nshttp.'absoluteURI', $val);
	
	$i = 1;
	foreach my $header ( $this->{RESPONSE}->headers->header_field_names )
	{
		my @h = $this->{RESPONSE}->header($header);
		foreach my $h (@h)
		{
			my $huri = consume_header($this, $Subject, $header, $h);
			$ResponseH->addVal('http://buzzword.org.uk/rdf/list-items/_'.$i,
				Swignition::RDFModel::Value->new($huri, 1));
			$i++;
		}
	}
	
	my $rdate = DateTime->from_epoch( epoch => $this->{RESPONSE}->headers->date);
	$rproto = $this->{RESPONSE}->protocol;
	$rproto =~ s|^HTTP/||;
	
	$val = Swignition::RDFModel::Value->new($rproto);
	$val->setDatatype('http://www.w3.org/2001/XMLSchema#float');
	$Response->addVal($nshttp.'httpVersion', $val) if ($rproto);
	$Response->addVal($nshttp.'statusCode',
		Swignition::RDFModel::Value->new($nshttpS.'statusCode'.$this->{RESPONSE}->code, 1));
	$val = Swignition::RDFModel::Value->new($this->{RESPONSE}->code);
	$val->setDatatype('http://www.w3.org/2001/XMLSchema#decimal');
	$Response->addVal($nshttp.'statusCodeNumber', $val);
	$Response->addVal($nshttp.'reasonPhrase',
		Swignition::RDFModel::Value->new($this->{RESPONSE}->message));
	$Response->addVal('http://purl.org/dc/terms/date',
		Swignition::RDFModel::Value->new($rdate));
	
	$this->mergeSubject($Subject);
	$this->mergeSubject($Request);
	$this->mergeSubject($RequestH);
	$this->mergeSubject($Response);
	$this->mergeSubject($ResponseH);
	
	$this->mergeNS('ianalink',
		'http://www.iana.org/assignments/relation/',
		'IANA Registered Link Types',
		-1,
		0);
	$this->mergeNS('ht',
		$nshttp,
		'HTTP Vocabulary in RDF',
		-1,
		0);
	$this->mergeNS('htx',
		'http://buzzword.org.uk/rdf/http-ext#',
		'HTTP Vocabulary in RDF Extentions',
		-1,
		0);
	$this->mergeNS('hth',
		$nshttpH,
		'HTTP Vocabulary in RDF (Headers)',
		-1,
		0);
	$this->mergeNS('htm',
		$nshttpM,
		'HTTP Vocabulary in RDF (Methods)',
		-1,
		0);
	$this->mergeNS('hts',
		$nshttpS,
		'HTTP Vocabulary in RDF (Status Codes)',
		-1,
		0);
}

sub relationship
{
	my $str   = shift;

	if ($str =~ /^([a-z][a-z0-9\+\.\-]*)\:/i)
	{
		# seems to be an absolute URI, so can safely return "as is".
		return $str;
	}

	return 'http://www.iana.org/assignments/relation/'.lc($str);

	my $url = url lc($str), 'http://www.iana.org/assignments/relation/';
	return $url->abs->as_string;

	return undef;
}

sub consume_header
{
	my $nsrdf   = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
	my $nshttp  = 'http://www.w3.org/2006/http#';
	my $nshttpH = 'http://www.w3.org/2008/http-headers#';
	my $nshttpM = 'http://www.w3.org/2008/http-methods#';
	my $nshttpS = 'http://www.w3.org/2008/http-statusCodes#';
	my $rdftype = $nsrdf.'type';

	my $this    = shift;
	my $Subject = shift;
	my $header  = shift;
	my $value   = shift;
	
	my $Header = Swignition::RDFModel::Subject->new(
		Swignition::GenericParser::Utils::BNodeURI(undef, 'MessageHeader'));
	$Header->addVal($rdftype,
		Swignition::RDFModel::Value->new($nshttp.'MessageHeader', 1));

	$Header->addVal($nshttp.'fieldName',
		Swignition::RDFModel::Value->new($header));
	$Header->addVal($nshttp.'headerName',
		Swignition::RDFModel::Value->new($nshttpH.lc($header), 1));
	my $val = Swignition::RDFModel::Value->new($value);
	$Header->addVal($nshttp.'fieldValue', $val);

	if ($header =~ /content-length/i)
	{
		$val->setDatatype('http://www.w3.org/2001/XMLSchema#nonNegitiveInteger');
	}
	elsif ($header =~ /(\bdate$)|(^last-modified$)|(^if-modified-since$)/i)
	{
		my $dt   = Swignition::uF::datetime($value);
		my $val2 = Swignition::RDFModel::Value->new($dt);
		$Header->addVal($nshttp.'fieldValue', $val2);
	}
	elsif ($header =~ /link/i)
	{
		my $h2 = $value;
		my $uri = undef;
		if ($h2 =~ /^(\s*<([^>]*)>\s*)/)
		{
			$uri = $2;
			$h2  = substr($value, length($1));
		}
		else
		{
			next;
		}
		
		my $ParamList = Swignition::RDFModel::Subject->new(
			Swignition::GenericParser::Utils::BNodeURI(undef, 'ParamList'));
		$ParamList->addVal($rdftype,
			Swignition::RDFModel::Value->new($nsrdf.'List', 1));

		my $HeaderElement = Swignition::RDFModel::Subject->new(
			Swignition::GenericParser::Utils::BNodeURI(undef, 'HeaderElement'));
		$HeaderElement->addVal($rdftype,
			Swignition::RDFModel::Value->new($nshttp.'HeaderElement', 1));
		$HeaderElement->addVal($nshttp.'elementName',
			Swignition::RDFModel::Value->new($uri));
		$HeaderElement->addVal($nshttp.'params',
			Swignition::RDFModel::Value->new($ParamList->uri, 1));

		my $HeaderElementList = Swignition::RDFModel::Subject->new(
			Swignition::GenericParser::Utils::BNodeURI(undef, 'HeaderElementList'));
		$HeaderElementList->addVal($rdftype,
			Swignition::RDFModel::Value->new($nsrdf.'List', 1));
		$HeaderElementList->addVal($nsrdf.'_1',
			Swignition::RDFModel::Value->new($HeaderElement->uri, 1));

		$Header->addVal($nshttp.'headerElements',
			Swignition::RDFModel::Value->new($HeaderElementList->uri, 1));
		
		$uri = $this->uri($uri);
		my $j = 1;
		while ($h2 =~ /^(\s*\;\s*(\/|[a-z0-9-]+)\s*\=\s*("[^"]*"|'[^']*'|[^\s\'\"\;\,]+)\s*)/i)
		{
			$h2 = substr($h2, length($1));
			my $key = $2;
			my $val = $3;

			$val =~ s/(^"|"$)//g if ($val =~ /^".*"$/);
			$val =~ s/(^'|'$)//g if ($val =~ /^'.*'$/ && $3 !~ /^".*"$/);

			my $Param = Swignition::RDFModel::Subject->new(
				Swignition::GenericParser::Utils::BNodeURI(undef, 'Param'));
			$Param->addVal($rdftype, Swignition::RDFModel::Value->new($nshttp.'Param', 1));
			$Param->addVal($nshttp.'paramName', Swignition::RDFModel::Value->new($key));
			$Param->addVal($nshttp.'paramValue', Swignition::RDFModel::Value->new($val));
			$ParamList->addVal('http://buzzword.org.uk/rdf/list-items/_'.$j, Swignition::RDFModel::Value->new($Param->uri, 1));
			$this->mergeSubject($Param);
			$j++;
			
			if (lc($key) eq 'rel')
			{
				my $Object  = Swignition::RDFModel::Value->new($uri, 1);

				$val =~ s/(^\s+)|(\s+$)//g;
				$val =~ s/\s+/ /g;
				
				my @rels = split / /, $val;
				foreach my $rel (@rels)
				{
					$Subject->addVal(relationship($rel), $Object);

					$this->{Profiles}->{$uri}
						if (lc($rel) eq 'profile');
				}
			}

			elsif (lc($key) eq 'rev')
			{
				my $Object  = Swignition::RDFModel::Subject->new($uri);

				$val =~ s/(^\s+)|(\s+$)//g;
				$val =~ s/\s+/ /g;
				
				my @rels = split / /, $val;
				foreach my $rel (@rels)
				{
					print "[[[$rel]]]\n";
					$Object->addVal(relationship($rel),
						Swignition::RDFModel::Value->new($Subject->uri, 1));
					$this->mergeSubject($Object);
				}
			}
		}
		
		$this->mergeSubject($HeaderElementList);
		$this->mergeSubject($HeaderElement);
		$this->mergeSubject($ParamList);
	}

	$this->mergeSubject($Header);
	
	return $Header->uri;
}

1;
